﻿//----------------------------------------------------------------------------
//  Copyright (C) 2004-2013 by EMGU. All rights reserved.       
//----------------------------------------------------------------------------

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using System.Drawing;
using helloworld2;
using System.Collections.Generic;
using helloworld2.MODEL;

namespace helloworld2
{

    class Image
    {
        private bool foundPattern = false;
        private static int cityCounter = 0; 
        private static int roadCounter = 1; // skal måske være 0!!!!
        private static KeyValuePair<int, int> currentPosition;
        private KeyValuePair<int, int> yx;
        private List<KeyValuePair<int, int>> purples = new List<KeyValuePair<int, int>>();
        private static List<KeyValuePair<int, int>> visitedStations = new List<KeyValuePair<int, int>>();
        private static List<KeyValuePair<int, int>> visitedCities = new List<KeyValuePair<int, int>>();
        private static List<KeyValuePair<int, int>> visitedRoads = new List<KeyValuePair<int, int>>();
        private static List<Object> allObjects = new List<object>();
        private int id = 0;
        
        private static List<KeyValuePair<int, int>> dontGoYellows = new List<KeyValuePair<int, int>>();
        private List<KeyValuePair<int, int>> newRoad = new List<KeyValuePair<int, int>>();
        private static string[] cities = { "Skagen", "Aalborg","Herning", "Aarhus","Vejle", "Koebenhavn", "Esbjerg", "Odense", "Aabenraa","Rødbyhavn"};
        private static Image<Bgr, Byte> img1 = new Image<Bgr, Byte>("C:/Users/Simonsk/Desktop/Electric car/trunk/Nicolai/Elbil/ElectricCar/ElectricCar/denmarkFinal.tif");
        //C:/Users/Simonsk/Desktop/Electric car/trunk/Nicolai/Elbil/ElectricCar/ElectricCar/denmarkFinal.tif   SIMONS
        //D:/UCN/3SemProjektwc/trunk/helloworld2/helloworld2/danmark3tif.tif   NICOLAIS
        //D:/Skole/El-cardos/trunk/Nicolai/Elbil/ElectricCar/ElectricCar/denmarkFinal.tif MARCKS
        private static bool reverse = false;

        private KeyValuePair<int, int> temp1;
        private KeyValuePair<int, int> temp2;

        StationContainer sc = StationContainer.Instance;
        RoadContainer rc = RoadContainer.Instance;
        EdgeContainer ec = EdgeContainer.Instance;
        VertexContainer vc = VertexContainer.Instance;
        int purpleCount = 0;
        int roadWidth = 0;
        bool checkPoint = false;
        bool isVisited;
        int seekX;
        int seekY;
        Bgr pink = new Bgr(201, 174, 255);
        Bgr red = new Bgr(36, 28, 237);
        Bgr yellow = new Bgr(0, 242, 255);
        Bgr orange = new Bgr(0, 128, 255);
        Bgr purple = new Bgr(164, 73, 163);
        Bgr blue = new Bgr(204, 72, 63);
        Bgr test;

        City start;
        City finish;
        CityContainer cc = CityContainer.Instance;

        //SINGLETON BEGIN --------------------------------------------------------
        private static Image instance=null;
        
        private Image()
        {
        }
        public static Image Instance
        {
            get
            {
                if (instance==null)
                {
                    instance = new Image();
                }
                return instance;
            }
        }
        //SINGLETON END -----------------------------------------------------------

        
        public void loadMap()
        {
            // ITERATE THROUGH ALL PIXELS, AND PAINT MAP!!
            //Hvis noget fucker up, så skal den køre loadMap 2 eller 3 gange!
            
                for (int y = 0; y < img1.Height; y++) //Y-scale
                {
                    for (int x = 0; x < img1.Width; x++) //X-scale
                    {
                        currentPosition = new KeyValuePair<int, int>(y, x);

                        if (img1[y, x].Equals(red))
                        {
                            locateCities(y, x);
                        }

                        else if (img1[y, x].Equals(purple))
                        {
                            isVisited = checkVisited(currentPosition, visitedRoads);
                            if (!isVisited)
                            {
                                locateRoad(y, x);
                            }
                        }

                        else if (img1[y, x].Equals(pink))
                        {
                            locateStations(y, x);
                        }
                    }
                }
            
            addConnections();
            addConnectionsToEdges();

            //Maler alle lilla til gule!!!!
            for (int y = 0; y < img1.Height; y++) //Y-scale
            {
                for (int x = 0; x < img1.Width; x++) //X-scale
                {
                    if (img1[y, x].Equals(purple))
                    {
                        img1[y, x] = yellow;
                    }
                }
            }
        }

        public void locateCities(int y, int x)
        {
            yx = new KeyValuePair<int, int>(y, x);
            isVisited = checkVisited(currentPosition, visitedCities);
            List<KeyValuePair<int, int>> field = new List<KeyValuePair<int, int>>();

            if (!isVisited)
            {
                for (int vy = y; vy < y + 7; vy++)
                {
                    for (int vx = x; vx < x + 7; vx++)
                    {
                        yx = new KeyValuePair<int, int>(vy, vx);
                        visitedCities.Add(yx);
                        field.Add(yx);                       
                    }
                }
                City c = new City(id ,cities[cityCounter], y + 3, x + 3, field); //+3 for the center of red square
                cc.addCity(c);
                allObjects.Add(c);

                id++;
                cityCounter++;
                //field.Clear();
            }
            //Console.WriteLine("FINAL VISITED" + visited.Count);
            //Console.WriteLine("current " + currentPosition);
        }

        public void locateStations(int y, int x)
        {
            yx = new KeyValuePair<int, int>(y, x);
            List<KeyValuePair<int, int>> field = new List<KeyValuePair<int, int>>();
            KeyValuePair<int, int> center = new KeyValuePair<int,int>(0,0);

            if (!visitedStations.Contains(yx))
            {
                for (int vy = y; vy < y + 3; vy++)
                {
                    for (int vx = x; vx < x + 3; vx++)
                    {
                        yx = new KeyValuePair<int, int>(vy, vx);
                        visitedStations.Add(yx);
                        field.Add(yx);

                        if (vy == y + 1 && vx == x + 1)
                        {
                            center = new KeyValuePair<int, int>(y, x);
                        }

                    }
                }
                Station s = new Station(id, field, center);
                sc.addStation(s);
                allObjects.Add(s);

                id++;
            }

        }

        public void locateRoad(int y, int x)
        {
            findPattern(y, x);
            foundPattern = false;
            findYellows(y, x);
            
                
            //Console.WriteLine("New road counter " + newRoad.Count);
            List<KeyValuePair<int, int>> newNewRoad = new List<KeyValuePair<int, int>>();
            foreach (KeyValuePair<int, int> kp in newRoad)
            {
                newNewRoad.Add(kp);
            }
            Road r = new Road(id, newNewRoad, null, null);
            rc.addRoad(r);

            allObjects.Add(r);
            id++;

            //for (int a = 0; a < newRoad.Count; a++)
            //{
            //    if (roadCounter % 2 != 0)
            //        test = orange;
            //    else
            //        test = blue;

            //    img1[newRoad[a].Key, newRoad[a].Value] = test;
            //}

            for (int b = 0; b < newRoad.Count; b++)
            {
                dontGoYellows.Add(newRoad[b]);               
            }
            newRoad.Clear();
            roadCounter++;
         
        }

        public void findPattern(int y, int x)
        {
            roadWidth++;
            yx = new KeyValuePair<int, int>(y, x);
            visitedRoads.Add(yx);
            newRoad.Add(yx);
            if (!foundPattern && roadWidth < 3)
            {
                if (img1[y, x + 1].Equals(purple))
                {
                    //Vertical road
                    //yx = new KeyValuePair<int, int>(y, x + 1); kan ikke lige se denne linie er nødvendig...
                    findPattern(y, x + 1);

                }
                else if (img1[y + 1, x + 1].Equals(purple))
                {
                    //SKRÅ MOD SYDVEST
                    //yx = new KeyValuePair<int, int>(y + 1, x + 1);
                    findPattern(y + 1, x + 1);
                }
                else if (img1[y + 1, x].Equals(purple))
                {
                    //HORIZONTAL ROAD MOD ØST
                    //yx = new KeyValuePair<int, int>(y + 1, x);
                    findPattern(y + 1, x);
                }

                else if (img1[y + 1, x - 1].Equals(purple))
                {
                    //Skrå vej mod sydøst
                    //yx = new KeyValuePair<int, int>(y + 1, x - 1);
                    findPattern(y + 1, x - 1);
                }
            }
            if (roadWidth == 3)
            {
                foundPattern = true;
                roadWidth = 0;
                //id++;
            }
        }


        public void findYellows(int y, int x)
        {
            bool onYellow = true;
            bool foundEnd;
            int newXRight = x;
            int newXLeft = x;
            int i;          

            while (onYellow)
            {
                yx = new KeyValuePair<int, int>(y, x);

                if (img1[y, x].Equals(yellow) && !dontGoYellows.Contains(yx)) //Hvis den lander i gul
                {
                    newRoad.Add(yx);
                }
                else if (img1[y, x].Equals(purple)) //Hvis det er en purple                           
                {
                    if (newRoad.Contains(yx)) //Hvis det er en af de 3 første purples
                    {

                    }

                    else //Hvis det er en slut purple              Den skal stadig søge 
                    {
                        break;
                    }
                }

                else //Hvis det er en hvid
                {
                    onYellow = false;
                }

                foundEnd = false;
                i = 1;
                while (!foundEnd) //Søg til højre
                {
                    yx = new KeyValuePair<int, int>(y, x + i);
                    if (img1[y, x + i].Equals(yellow) && !dontGoYellows.Contains(yx)) //Finder gul
                    {
                        newRoad.Add(yx);
                    }

                    else if (img1[y, x + i].Equals(purple) && newRoad.Contains(yx)) //Finder start lilla
                    {
                    }

                    else if (img1[y, x + i].Equals(purple) && !newRoad.Contains(yx)) //Finder slut lilla
                    {
                        //CheckSquare(y, x + i);
                        foundEnd = true;
                        newXRight = x + i;
                    }

                    else //Finder hvid
                    {
                        foundEnd = true;
                        newXRight = x + i - 1;
                    }
                    i++;
                }

                foundEnd = false;
                i = 1;
                while (!foundEnd) //Søg til venstre
                {
                    yx = new KeyValuePair<int, int>(y, x - i);
                    if (img1[y, x - i].Equals(yellow) && !dontGoYellows.Contains(yx)) //Finder gul       
                    {
                        newRoad.Add(yx);
                    }

                    else if (img1[y, x - i].Equals(purple) && newRoad.Contains(yx)) //Finder start lilla
                    {
                    }

                    else if (img1[y, x - i].Equals(purple) && !newRoad.Contains(yx)) //Finder slut lilla
                    {
                        //CheckSquare(y, x - i);
                        foundEnd = true;
                        newXLeft = x - i;
                    }

                    else //Finder hvid
                    {
                        foundEnd = true;
                        newXLeft = x - i + 1;
                    }
                    i++;
                }



                int newX = ((newXRight - newXLeft) / 2) + newXLeft;
                x = newX;

                if (!img1[y + 1, newX].Equals(yellow) || !img1[y + 1, newX].Equals(purple))
                {
                    for (int k = 1; k < (newXRight - newXLeft) / 2; k++)
                    {
                        if (img1[y + 1, newX - k].Equals(yellow))
                        {
                            x = newX - k;
                        }
                        else if (img1[y + 1, newX + k].Equals(yellow))
                        {
                            x = newX + k;
                        }
                    }
                }
                y++;
                
            }
        }

        public void addConnections()
        {
            foreach (Road r in rc.getRoads())
            {              
                KeyValuePair<int, int> firstYX = r.getIndexOfField(0);
                KeyValuePair<int, int> newYX = new KeyValuePair<int, int>();
                bool check = checkVisited(firstYX, r.getField());
                newYX = new KeyValuePair<int, int>(firstYX.Key, firstYX.Value + 1);

                if (img1[newYX.Key, newYX.Value].Equals(red) || img1[newYX.Key, newYX.Value].Equals(pink) || img1[newYX.Key, newYX.Value].Equals(yellow) && !r.getField().Contains(newYX))
                {
                    Object conr = findObjectFromCoordinates(newYX, r);
                    r.addConnection(conr);
                }
                newYX = new KeyValuePair<int, int>(firstYX.Key, firstYX.Value - 1);
                if (img1[newYX.Key, newYX.Value].Equals(red) || img1[newYX.Key, newYX.Value].Equals(pink) || img1[newYX.Key, newYX.Value].Equals(yellow) && !r.getField().Contains(newYX))
                {
                    Object conr = findObjectFromCoordinates(newYX, r);
                    r.addConnection(conr);
                }
                newYX = new KeyValuePair<int, int>(firstYX.Key + 1, firstYX.Value);
                if (img1[newYX.Key, newYX.Value].Equals(red) || img1[newYX.Key, newYX.Value].Equals(pink) || img1[newYX.Key, newYX.Value].Equals(yellow) && !r.getField().Contains(newYX))
                {
                    Object conr = findObjectFromCoordinates(newYX, r);
                    r.addConnection(conr);
                }
                newYX = new KeyValuePair<int, int>(firstYX.Key - 1, firstYX.Value);
                if (img1[newYX.Key, newYX.Value].Equals(red) || img1[newYX.Key, newYX.Value].Equals(pink) || img1[newYX.Key, newYX.Value].Equals(yellow) && !r.getField().Contains(newYX))
                {
                    Object conr = findObjectFromCoordinates(newYX, r);     
                    r.addConnection(conr);
                }
            }
        }

        private void addConnectionsToEdges()
        {
            foreach (Vertex v in vc.getVertices())
            {
                //Ned
                if (img1[v.getCenter().Key + 1, v.getCenter().Value].Equals(red))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key + 1, v.getCenter().Value);
                    City c = cc.getCityByCoordinates(yx);
                    Edge e = ec.getEdgeByID(c.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                if (img1[v.getCenter().Key + 1, v.getCenter().Value].Equals(pink))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key + 1, v.getCenter().Value);
                    Station s = sc.getStationByCoordinates(yx);
                    Edge e = ec.getEdgeByID(s.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                if (img1[v.getCenter().Key + 1, v.getCenter().Value].Equals(yellow))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key + 1, v.getCenter().Value);
                    Road r = rc.getRoadByCoordinates(yx);
                    Edge e = ec.getEdgeByID(r.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                //Op
                if (img1[v.getCenter().Key - 1, v.getCenter().Value].Equals(red))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key - 1, v.getCenter().Value);
                    City c = cc.getCityByCoordinates(yx);
                    Edge e = ec.getEdgeByID(c.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                if (img1[v.getCenter().Key - 1, v.getCenter().Value].Equals(pink))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key - 1, v.getCenter().Value);
                    Station s = sc.getStationByCoordinates(yx);
                    Edge e = ec.getEdgeByID(s.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                if (img1[v.getCenter().Key - 1, v.getCenter().Value].Equals(yellow))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key - 1, v.getCenter().Value);
                    Road r = rc.getRoadByCoordinates(yx);
                    Edge e = ec.getEdgeByID(r.id);
                    //Console.WriteLine("edge id " + e.id + " edge length " + e.length);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                //Højre
                if (img1[v.getCenter().Key, v.getCenter().Value + 1].Equals(red))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key, v.getCenter().Value + 1);
                    City c = cc.getCityByCoordinates(yx);
                    Edge e = ec.getEdgeByID(c.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                if (img1[v.getCenter().Key, v.getCenter().Value +1].Equals(pink))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key, v.getCenter().Value + 1);
                    Station s = sc.getStationByCoordinates(yx);
                    Edge e = ec.getEdgeByID(s.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                if (img1[v.getCenter().Key, v.getCenter().Value +1].Equals(yellow))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key, v.getCenter().Value + 1);
                    Road r = rc.getRoadByCoordinates(yx);
                    Edge e = ec.getEdgeByID(r.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                //Venstre
                if (img1[v.getCenter().Key, v.getCenter().Value - 1].Equals(red))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key, v.getCenter().Value - 1);
                    City c = cc.getCityByCoordinates(yx);
                    Edge e = ec.getEdgeByID(c.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                if (img1[v.getCenter().Key, v.getCenter().Value - 1].Equals(pink))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key, v.getCenter().Value - 1);
                    Station s = sc.getStationByCoordinates(yx);
                    Edge e = ec.getEdgeByID(s.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }
                if (img1[v.getCenter().Key, v.getCenter().Value - 1].Equals(yellow))
                {
                    yx = new KeyValuePair<int, int>(v.getCenter().Key, v.getCenter().Value - 1);
                    Road r = rc.getRoadByCoordinates(yx);
                    Edge e = ec.getEdgeByID(r.id);
                    v.addConnection(e);
                    e.addConnection(v);
                }

            }
        }

        private Object findObjectFromCoordinates(KeyValuePair<int, int> coordinates, Road r)
        {
            Object o = new Object();
            if (img1[coordinates.Key, coordinates.Value].Equals(red))
            {
                City c = cc.getCityByCoordinates(coordinates);
                o = o as City;
                o = c;
                c.addConnection(r);
            }
            else if (img1[coordinates.Key, coordinates.Value].Equals(yellow))
            {
                Road road = rc.getRoadByCoordinates(coordinates);
                o = o as Road;
                o = road;
            }
            else if (img1[coordinates.Key, coordinates.Value].Equals(pink))
            {
                Station s = sc.getStationByCoordinates(coordinates);
                o = o as Station;
                o = s;
                s.addConnection(r);
            }

            return o;
        }

        public bool checkVisited(KeyValuePair<int, int> yx, List<KeyValuePair<int, int>> listToCheck)
        {
            bool isVisited = false;
            for (int i = 0; i < listToCheck.Count; i++)
            {
                if (yx.Equals(listToCheck[i]) && !isVisited)
                {
                    isVisited = true;
                }
            }
            return isVisited;
        }

        public void drawPath(List<Vertex> path)
        {
            List<Edge> edgeList = new List<Edge>();
            foreach (Vertex v in path)
            {
                foreach (KeyValuePair<int, int> kp in v.getField())
                {
                    img1[kp.Key, kp.Value] = blue;
                }

                foreach(Edge e in v.getConnection())
                {
                    foreach (Vertex ev in e.getConnection())
                    {
                        if(path.Contains(ev) && !edgeList.Contains(e))
                        {
                            edgeList.Add(e);
                        }
                    }
                }
            }
            foreach (Edge e in edgeList)
            {
                foreach (Road r in rc.getRoads())
                {
                    if (e.id == r.id)
                    {
                        foreach (KeyValuePair<int, int> kp in r.getField())
                        {
                            img1[kp.Key, kp.Value] = blue;
                        }
                    }
                }
               
            }
        }

        public List<Vertex> getNearbyStations(KeyValuePair<int,int> sCord) //sourceCoordinate
        {

            List<Vertex> nStations = new List<Vertex>();
            double a;
            double b;

            foreach (Station s in sc.getStations())
            {


                if (sCord.Value > s.center.Value)
                {
                    a = sCord.Value - s.center.Value;
                }

                else
                {
                    a = s.center.Value - sCord.Value;
                }

                if (sCord.Key > s.center.Key)
                {
                    b = sCord.Key - s.center.Key;
                }

                else
                {
                    b = s.center.Key - sCord.Key;
                }

                double result = Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2));
                result = result * 1.2;

                if (result < 100)
                {
                    List<KeyValuePair<int, int>> field = new List<KeyValuePair<int, int>>();
                    field.Add(s.center);
                    Vertex v = new Vertex(field, vc.getVertices().Count+1);
                    nStations.Add(v);
                }
            }

            return nStations;
        }
        

        public Image<Bgr, Byte> getImage() {
            return img1;
        }

        public void findRoute(string startCity, string finishCity)
        {
            this.start = cc.findCity(startCity);
            this.finish = cc.findCity(finishCity);

            Console.WriteLine(start.name + start.getCoordinates());
            Console.WriteLine(finish.name + finish.getCoordinates());

            Edge es = ec.getEdgeByID(start.id);
            Edge ef = ec.getEdgeByID(finish.id);

            List<KeyValuePair<int, int>> cityList = new List<KeyValuePair<int, int>>();
            cityList.Add(start.getCoordinates());


            Vertex startV = new Vertex(cityList, vc.getVertices().Count+1);
            startV.addConnection(es);

            cityList.Clear();
            cityList.Add(finish.getCoordinates());

            Vertex endV = new Vertex(cityList, vc.getVertices().Count+1);
            endV.addConnection(ef);

            es.addConnection(startV);
            ef.addConnection(endV);

            Console.WriteLine("pathfinder begin");
            PathFinder p = new PathFinder(startV, endV);      

        }    
    }
}

